package cn.base.web.support.filter;

import cn.rengy.util.servlet.ServletUtil;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;

/**
 * 可重复读取HttpServletRequest
 * ContentCachingRequestWrapper无效
 */
@Slf4j
public class MultiReadHttpServletRequestWrapper extends HttpServletRequestWrapper {
	private static final Logger LOGGER = LoggerFactory.getLogger(MultiReadHttpServletRequestWrapper.class);
	HttpServletRequest orgRequest = null;//原始request
    private byte[] cachedBytes=null;//request的body缓存

    public MultiReadHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
    	super(request);
    	orgRequest=request;
    	Enumeration<String> headerNames=request.getHeaderNames();
		//缓存数据使ServletInputStream可以重复读取
    	cachePayload();
    }

    private void cachePayload() throws IOException{

    	//非上传文件 & 返回json
        if(!ServletUtil.isUploadRequest(orgRequest)&&ServletUtil.isAjaxRequest(orgRequest)){
            //tomcat org.apache.catalina.connector.Request 的getParameter有bug，如果调用过getInputStream方法，认为getParameter已经缓存，导致无法获取参数
            //问题代码在Request的parseParameters方法 1960行
            super.getParameter("TomcatGetParameterBug");//解决tomcat getParameter没有值bug
            cachedBytes=IOUtils.toByteArray(super.getInputStream());
            //TODO ajax请求对payload数据进行xss过滤
            //String json=IOUtils.toString(buffer,"utf-8");
            //为空，直接返回

            //xss过滤
            //json = cleanPayload(json);
            //this.buffer=json.getBytes("utf-8");
        }
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        if(cachedBytes==null){
            return orgRequest.getInputStream();
        }else{
            return new CachedServletInputStream(this.cachedBytes);
        }
    }
    class CachedServletInputStream extends ServletInputStream {
        private final ByteArrayInputStream inputStream;
        public CachedServletInputStream(byte[] buffer){
            this.inputStream = new ByteArrayInputStream(buffer);
        }
		@Override
		public boolean isFinished() {
			return inputStream.available()==0;
		}
		@Override
		public boolean isReady() {
			return true;
		}
		@Override
		public void setReadListener(ReadListener listener) {
            throw new RuntimeException("CachedServletInputStream Not implemented");
		}
		@Override
		public int read() throws IOException {
			return inputStream.read();
		}
    }


   @Override
    public String[] getParameterValues(String parameter) {
        return super.getParameterValues(parameter);
    }

    @Override
    public Map<String,String[]> getParameterMap() {
        return super.getParameterMap();
    }

    @Override
    public String getParameter(String parameter) {
        return  super.getParameter(parameter);
    }

    @Override
    public String getHeader(String name) {
        return super.getHeader(name);
    }

    @Override
    public Cookie[] getCookies() {
        return super.getCookies();
    }




    /*private String xssEncode(String input) {
        // 过滤XSS
        return SimpleXssFilterUtils.clean(input);
        //return StringEscapeUtils.escapeHtml4(value);
    }*/
    /**
     * 获取最原始的request
     */
    public HttpServletRequest getOrgRequest() {
        return orgRequest;
    }

    /**
     * 获取最原始的request
     */
    public HttpServletRequest getOrgRequest(HttpServletRequest request) {
        if (request instanceof MultiReadHttpServletRequestWrapper) {
            return ((MultiReadHttpServletRequestWrapper) request).getOrgRequest();
        }
        return request;
    }

    /*private String cleanParam(String input){
    	return clean(input,0);
    }
    private static String clean(String input,int type) {
        if (input == null) {
            return null;
        }
        StringBuilder sb = new StringBuilder(input.length()+16);
        for (int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);
            //if (type == 0) {//param参数
            //	return StringEscapeUtils.escapeHtml4(input);
            //}else{//payload参数
            	switch (c) {
                case '<':
                	sb.append("&lt;");
                    break;
                case '>':
                	sb.append("&gt;");
                    break;
//                case '%':
//                	processUrlEncoder( sb,  input,  i);
//                	break;
//                case '&':
//                	sb.append("&amp;");
//                    break;
                default:
                	sb.append(c);
                }
            //}
        }
        return sb.toString();
    }
    private String cleanPayload(String input){
    	return input;
    	//return clean(input,1);
    }
    private static void processUrlEncoder(StringBuilder sb, String s, int index) {
        if (s.length() >= index + 2) {
            // %3c, %3C
            if (s.charAt(index + 1) == '3' && (s.charAt(index + 2) == 'c' || s.charAt(index + 2) == 'C')) {
                sb.append("&lt;");//'＜'
                //TODO i=i+2
                return;
            }
            // %3c (0x3c=60)
            if (s.charAt(index + 1) == '6' && s.charAt(index + 2) == '0') {
                sb.append("&lt;");//'＜'
              //TODO i=i+2
                return;
            }
            // %3e, %3E
            if (s.charAt(index + 1) == '3' && (s.charAt(index + 2) == 'e' || s.charAt(index + 2) == 'E')) {
                sb.append("&gt;");//'＞'
                //TODO i=i+2
                return;
            }
            // %3e (0x3e=62)
            if (s.charAt(index + 1) == '6' && s.charAt(index + 2) == '2') {
                sb.append("&gt;");//'＞'
               //TODO i=i+2
                return;
            }
        }
        sb.append(s.charAt(index));
    }*/
}
